home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / oct-stream.cc < prev    next >
C/C++ Source or Header  |  1997-03-07  |  48KB  |  2,754 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. #ifdef HAVE_CONFIG_H
  24. #include <config.h>
  25. #endif
  26.  
  27. #include <cstring>
  28.  
  29. #include <iomanip.h>
  30. #include <strstream.h>
  31.  
  32. #include "lo-ieee.h"
  33. #include "lo-mappers.h"
  34. #include "lo-utils.h"
  35. #include "str-vec.h"
  36.  
  37. #include "error.h"
  38. #include "oct-stream.h"
  39. #include "utils.h"
  40.  
  41. // Possible values for conv_err:
  42. //
  43. //   1 : not a real scalar
  44. //   2 : error extracting scalar value (should not happen)
  45. //   3 : value is NaN
  46. //   4 : value is not an integer
  47.  
  48. static int
  49. convert_to_valid_int (const octave_value& tc, int& conv_err)
  50. {
  51.   int retval = 0;
  52.  
  53.   conv_err = 0;
  54.  
  55.   if (tc.is_real_scalar ())
  56.     {
  57.       double dval = tc.double_value ();
  58.  
  59.       if (! error_state)
  60.     {
  61.       if (! xisnan (dval))
  62.         {
  63.           int ival = NINT (dval);
  64.  
  65.           if ((double) ival == dval)
  66.         retval = ival;
  67.           else
  68.         conv_err = 4;
  69.         }
  70.       else
  71.         conv_err = 3;
  72.     }
  73.       else
  74.     conv_err = 2;
  75.     }
  76.   else
  77.     conv_err = 1;
  78.  
  79.   return retval;
  80. }
  81.  
  82. static int
  83. get_size (double d, const char *warn_for)
  84. {
  85.   int retval = -1;
  86.  
  87.   if (! xisnan (d))
  88.     {
  89.       if (! xisinf (d))
  90.     {
  91.       if (d > 0.0)
  92.         retval = NINT (d);
  93.       else
  94.         ::error ("%s: negative value invalid as size specification",
  95.              warn_for);
  96.     }
  97.       else
  98.     retval = -1;
  99.     }
  100.   else
  101.     ::error ("%s: NaN is invalid as size specification", warn_for);
  102.  
  103.   return retval;
  104. }
  105.  
  106. static void
  107. get_size (const Matrix& size, int& nr, int& nc, const char *warn_for)
  108. {
  109.   nr = -1;
  110.   nc = -1;
  111.  
  112.   double dnr = -1.0;
  113.   double dnc = -1.0;
  114.  
  115.   int sz_nr = size.rows ();
  116.   int sz_nc = size.cols ();
  117.  
  118.   if (sz_nr == 1 && sz_nc == 1)
  119.     {
  120.       dnr = size (0, 0);
  121.       dnc = 1.0;
  122.     }
  123.   else if (sz_nr == 1 && sz_nc > 0)
  124.     {
  125.       dnr = size (0, 0);
  126.  
  127.       if (sz_nc == 2)
  128.     dnc = size (0, 1);
  129.       else if (sz_nc > 2)
  130.     ::error ("%s: invalid size specification", warn_for);
  131.     }
  132.   else if (sz_nc == 1 && sz_nr > 0)
  133.     {
  134.       dnr = size (0, 0);
  135.  
  136.       if (sz_nr == 2)
  137.     dnc = size (1, 0);
  138.       else if (sz_nr > 2)
  139.     ::error ("%s: invalid size specification", warn_for);
  140.     }
  141.   else
  142.     ::error ("%s: invalid size specification", warn_for);
  143.  
  144.   if (! error_state)
  145.     {
  146.       nr = get_size (dnr, warn_for);
  147.  
  148.       if (! error_state && dnc > 0.0)
  149.     nc = get_size (dnc, warn_for);
  150.     }
  151. }
  152.  
  153. scanf_format_list::scanf_format_list (const string& s)
  154.   : nconv (0), curr_idx (0), list (16), buf (0)
  155. {
  156.   int num_elts = 0;
  157.  
  158.   int n = s.length ();
  159.  
  160.   int i = 0;
  161.  
  162.   int width = 0;
  163.   bool discard = false;
  164.   char modifier = '\0';
  165.   char type = '\0';
  166.  
  167.   bool have_more = true;
  168.  
  169.   while (i < n)
  170.     {
  171.       have_more = true;
  172.  
  173.       if (! buf)
  174.     buf = new ostrstream ();
  175.  
  176.       if (s[i] == '%')
  177.     {
  178.       process_conversion (s, i, n, width, discard, type, modifier,
  179.                   num_elts);
  180.       have_more = (buf != 0);
  181.     }
  182.       else
  183.     {
  184.       width = 0;
  185.       discard = false;
  186.       modifier = '\0';
  187.       type = '\0';
  188.       *buf << s[i++];
  189.     }
  190.  
  191.       if (nconv < 0)
  192.     {
  193.       have_more = false;
  194.       break;
  195.     }
  196.     }
  197.  
  198.   if (have_more)
  199.     add_elt_to_list (width, discard, type, modifier, num_elts);
  200.  
  201.   list.resize (num_elts);
  202.  
  203.   delete buf;
  204. }
  205.  
  206. scanf_format_list::~scanf_format_list (void)
  207. {
  208.   int n = list.length ();
  209.  
  210.   for (int i = 0; i < n; i++)
  211.     {
  212.       scanf_format_elt *elt = list (i);
  213.       delete elt;
  214.     }    
  215. }
  216.  
  217. void
  218. scanf_format_list::add_elt_to_list (int width, bool discard, char type,
  219.                     char modifier, int& num_elts)
  220. {
  221.   if (buf)
  222.     {
  223.       *buf << ends;
  224.  
  225.       char *text = buf->str ();
  226.  
  227.       if (text)
  228.     {
  229.       if (*text)
  230.         {
  231.           scanf_format_elt *elt
  232.         = new scanf_format_elt (text, width, discard, type, modifier);
  233.  
  234.           if (num_elts == list.length ())
  235.         list.resize (2 * num_elts);
  236.  
  237.           list (num_elts++) = elt;
  238.         }
  239.       else
  240.         delete [] text;
  241.     }
  242.  
  243.       delete buf;
  244.       buf = 0;
  245.     }
  246. }
  247.  
  248. void
  249. scanf_format_list::process_conversion (const string& s, int& i, int n,
  250.                        int& width, bool& discard, char& type,
  251.                        char& modifier, int& num_elts)
  252.  
  253. {
  254.   width = 0;
  255.   discard = false;
  256.   modifier = '\0';
  257.   type = '\0';
  258.  
  259.   *buf << s[i++];
  260.  
  261.   bool have_width = false;
  262.  
  263.   while (i < n)
  264.     {
  265.       switch (s[i])
  266.     {
  267.     case '*':
  268.       if (discard)
  269.         nconv = -1;
  270.       else
  271.         {
  272.           discard = true;
  273.           *buf << s[i++];
  274.         }
  275.       break;
  276.  
  277.     case '0': case '1': case '2': case '3': case '4':
  278.     case '5': case '6': case '7': case '8': case '9':
  279.       if (have_width)
  280.         nconv = -1;
  281.       else
  282.         {
  283.           char c = s[i++];
  284.           width = width * 10 + c - '0';
  285.           have_width = true;
  286.           *buf << c;
  287.           while (i < n && isdigit (s[i]))
  288.         {
  289.           c = s[i++];
  290.           width = width * 10 + c - '0';
  291.           *buf << c;
  292.         }
  293.         }
  294.       break;
  295.  
  296.     case 'h': case 'l': case 'L':
  297.       // We accept these but we don't actually use them.
  298.       if (modifier != '\0')
  299.         nconv = -1;
  300.       else
  301.         modifier = s[i++];
  302.       break;
  303.  
  304.     case 'd': case 'i': case 'o': case 'u': case 'x':
  305.       if (modifier == 'L')
  306.         {
  307.           nconv = -1;
  308.           break;
  309.         }
  310.       goto fini;
  311.  
  312.     case 'e': case 'f': case 'g':
  313.       if (modifier == 'h')
  314.         {
  315.           nconv = -1;
  316.           break;
  317.         }
  318.  
  319.       // No float or long double conversions, thanks.
  320.       *buf << 'l';
  321.  
  322.       goto fini;
  323.  
  324.     case 'c': case 's': case 'p': case '%': case '[':
  325.       if (modifier != '\0')
  326.         {
  327.           nconv = -1;
  328.           break;
  329.         }
  330.       goto fini;
  331.  
  332.     fini:
  333.       {
  334.         if (finish_conversion (s, i, n, width, discard, type,
  335.                    modifier, num_elts) == 0)
  336.           return;
  337.       }
  338.       break;
  339.  
  340.     default:
  341.       nconv = -1;
  342.       break;
  343.     }
  344.  
  345.       if (nconv < 0)
  346.     break;
  347.     }
  348.  
  349.   nconv = -1;
  350. }
  351.  
  352. int
  353. scanf_format_list::finish_conversion (const string& s, int& i, int n,
  354.                       int& width, bool discard, char& type,
  355.                       char modifier, int& num_elts)
  356. {
  357.   int retval = 0;
  358.  
  359.   if (s[i] == '%')
  360.     *buf << s[i++];
  361.   else
  362.     {
  363.       type = s[i];
  364.  
  365.       if (s[i] == '[')
  366.     {
  367.       *buf << s[i++];
  368.  
  369.       if (i < n)
  370.         {
  371.           if (s[i] == '^')
  372.         {
  373.           type = '^';
  374.           *buf << s[i++];
  375.         }
  376.           else if (s[i] == ']')
  377.         *buf << s[i++];
  378.         }
  379.  
  380.       while (i < n && s[i] != ']')
  381.         *buf << s[i++];
  382.  
  383.       if (i < n && s[i] == ']')
  384.         *buf << s[i++];
  385.  
  386.       if (s[i-1] != ']')
  387.         retval = nconv = -1;
  388.     }
  389.       else
  390.     *buf << s[i++];
  391.  
  392.       nconv++;
  393.  
  394.       if (nconv > 0)
  395.     add_elt_to_list (width, discard, type, modifier, num_elts);
  396.     }
  397.  
  398.   return retval;
  399. }
  400.  
  401. void
  402. scanf_format_list::printme (void) const
  403. {
  404.   int n = list.length ();
  405.  
  406.   for (int i = 0; i < n; i++)
  407.     {
  408.       scanf_format_elt *elt = list (i);
  409.  
  410.       cerr << elt->width << "\t"
  411.        << elt->discard << "\t"
  412.        << elt->type << "\t"
  413.        << elt->modifier << "\t"
  414.        << undo_string_escapes (elt->text) << "\n";
  415.     }
  416. }
  417.  
  418. bool
  419. scanf_format_list::all_character_conversions (void)
  420. {
  421.   int n = list.length ();
  422.  
  423.   if (n > 0)
  424.     {
  425.       for (int i = 0; i < n; i++)
  426.     {
  427.       scanf_format_elt *elt = list (i);
  428.  
  429.       switch (elt->type)
  430.         {
  431.         case 'c': case 's': case 'p': case '%': case '[':
  432.           break;
  433.  
  434.         default:
  435.           return false;
  436.           break;
  437.         }
  438.     }
  439.  
  440.       return true;
  441.     }
  442.   else
  443.     return false;
  444. }
  445.  
  446. bool
  447. scanf_format_list::all_numeric_conversions (void)
  448. {
  449.   int n = list.length ();
  450.  
  451.   if (n > 0)
  452.     {
  453.       for (int i = 0; i < n; i++)
  454.     {
  455.       scanf_format_elt *elt = list (i);
  456.  
  457.       switch (elt->type)
  458.         {
  459.         case 'd': case 'i': case 'o': case 'u': case 'x':
  460.         case 'e': case 'f': case 'g':
  461.           break;
  462.  
  463.         default:
  464.           return false;
  465.           break;
  466.         }
  467.     }
  468.  
  469.       return true;
  470.     }
  471.   else
  472.     return false;
  473. }
  474.  
  475. // Ugh again.
  476.  
  477. printf_format_list::printf_format_list (const string& s)
  478.   : nconv (0), curr_idx (0), list (16), buf (0)
  479. {
  480.   int num_elts = 0;
  481.  
  482.   int n = s.length ();
  483.  
  484.   int i = 0;
  485.  
  486.   int args = 0;
  487.   char modifier = '\0';
  488.   char type = '\0';
  489.  
  490.   bool have_more = true;
  491.  
  492.   while (i < n)
  493.     {
  494.       have_more = true;
  495.  
  496.       if (! buf)
  497.     buf = new ostrstream ();
  498.  
  499.       switch (s[i])
  500.     {
  501.     case '%':
  502.       process_conversion (s, i, n, args, type, modifier, num_elts);
  503.       have_more = (buf != 0);
  504.       break;
  505.  
  506.     default:
  507.       args = 0;
  508.       modifier = '\0';
  509.       type = '\0';
  510.       *buf << s[i++];
  511.       break;
  512.     }
  513.  
  514.       if (nconv < 0)
  515.     {
  516.       have_more = false;
  517.       break;
  518.     }
  519.     }
  520.  
  521.   if (have_more)
  522.     add_elt_to_list (args, type, modifier, num_elts);
  523.  
  524.   list.resize (num_elts);
  525.  
  526.   delete buf;
  527. }
  528.  
  529. printf_format_list::~printf_format_list (void)
  530. {
  531.   int n = list.length ();
  532.  
  533.   for (int i = 0; i < n; i++)
  534.     {
  535.       printf_format_elt *elt = list (i);
  536.       delete elt;
  537.     }    
  538. }
  539.  
  540. void
  541. printf_format_list::add_elt_to_list (int args, char type, char modifier,
  542.                      int& num_elts)
  543. {
  544.   if (buf)
  545.     {
  546.       *buf << ends;
  547.  
  548.       char *text = buf->str ();
  549.  
  550.       if (text)
  551.     {
  552.       if (*text)
  553.         {
  554.           printf_format_elt *elt
  555.         = new printf_format_elt (text, args, type, modifier);
  556.  
  557.           if (num_elts == list.length ())
  558.         list.resize (2 * num_elts);
  559.  
  560.           list (num_elts++) = elt;
  561.         }
  562.       else
  563.         delete [] text;
  564.     }
  565.  
  566.       delete buf;
  567.       buf = 0;
  568.     }
  569. }
  570.  
  571. void
  572. printf_format_list::process_conversion (const string& s, int& i, int n,
  573.                     int& args, char& modifier,
  574.                     char& type, int& num_elts)
  575. {
  576.   args = 0;
  577.   modifier = '\0';
  578.   type = '\0';
  579.  
  580.   *buf << s[i++];
  581.  
  582.   bool next = false;
  583.  
  584.   while (i < n)
  585.     {
  586.       switch (s[i])
  587.     {
  588.     case '-': case '+': case ' ': case '0': case '#':
  589.       *buf << s[i++];
  590.       break;
  591.  
  592.     default:
  593.       next = true;
  594.       break;
  595.     }
  596.  
  597.       if (next)
  598.     break;
  599.     }
  600.  
  601.   if (i < n)
  602.     {
  603.       if (s[i] == '*')
  604.     {
  605.       args++;
  606.       *buf << s[i++];
  607.     }
  608.       else
  609.     {
  610.       while (i < n && isdigit (s[i]))
  611.         *buf << s[i++];
  612.     }
  613.     }
  614.  
  615.   if (i < n && s[i] == '.')
  616.     {
  617.       *buf << s[i++];
  618.  
  619.       if (i < n)
  620.     {
  621.       if (s[i] == '*')
  622.         {
  623.           args++;
  624.           *buf << s[i++];
  625.         }
  626.       else
  627.         {
  628.           while (i < n && isdigit (s[i]))
  629.         *buf << s[i++];
  630.         }
  631.     }
  632.     }
  633.  
  634.   if (i < n)
  635.     {
  636.       switch (s[i])
  637.     {
  638.     case 'h': case 'l': case 'L':
  639.       modifier = s[i];
  640.       *buf << s[i++];
  641.       break;
  642.  
  643.     default:
  644.       break;
  645.     }
  646.     }
  647.  
  648.   if (i < n)
  649.     finish_conversion (s, i, args, modifier, type, num_elts);
  650.   else
  651.     nconv = -1;
  652. }
  653.  
  654. void
  655. printf_format_list::finish_conversion (const string& s, int& i,
  656.                        int args, char modifier,
  657.                        char& type, int& num_elts)
  658.  
  659. {
  660.   switch (s[i])
  661.     {
  662.     case 'd': case 'i': case 'o': case 'x': case 'X':
  663.     case 'u': case 'c':
  664.       if (modifier == 'L')
  665.     {
  666.       nconv = -1;
  667.       break;
  668.     }
  669.       goto fini;
  670.  
  671.     case 'f': case 'e': case 'E': case 'g': case 'G':
  672.       if (modifier == 'h' || modifier == 'l')
  673.     {
  674.       nconv = -1;
  675.       break;
  676.     }
  677.       goto fini;
  678.  
  679.     case 's': case 'p': case '%':
  680.       if (modifier != '\0')
  681.     {
  682.       nconv = -1;
  683.       break;
  684.     }
  685.       goto fini;
  686.  
  687.     fini:
  688.  
  689.       if (s[i] == '%' && args == 0)
  690.     *buf << s[i++];
  691.       else
  692.     {
  693.       if (s[i] != '%')
  694.         args++;
  695.  
  696.       type = s[i];
  697.  
  698.       *buf << s[i++];
  699.  
  700.       add_elt_to_list (args, type, modifier, num_elts);
  701.  
  702.       nconv++;
  703.     }
  704.       break;
  705.  
  706.     default:
  707.       nconv = -1;
  708.       break;
  709.     }
  710. }
  711.  
  712. void
  713. printf_format_list::printme (void) const
  714. {
  715.   int n = list.length ();
  716.  
  717.   for (int i = 0; i < n; i++)
  718.     {
  719.       printf_format_elt *elt = list (i);
  720.  
  721.       cerr << elt->args<< "\t"
  722.        << elt->type << "\t"
  723.        << elt->modifier << "\t"
  724.        << undo_string_escapes (elt->text) << "\n";
  725.     }
  726. }
  727.  
  728. void
  729. octave_base_stream::error (const string& msg)
  730. {
  731.   fail = true;
  732.   errmsg = msg;
  733. }
  734.  
  735. void
  736. octave_base_stream::clear (void)
  737. {
  738.   fail = false;
  739.   errmsg = "";
  740. }
  741.  
  742. // Functions that are defined for all input streams (input streams
  743. // are those that define is).
  744.  
  745. string
  746. octave_base_stream::do_gets (int max_len, bool& err,
  747.                  bool strip_newline, const char *fcn)
  748. {
  749.   string retval;
  750.  
  751.   err = false;
  752.  
  753.   istream *isp = input_stream ();
  754.  
  755.   if (isp)
  756.     {
  757.       istream& is = *isp;
  758.  
  759.       // XXX FIXME XXX -- this should probably be converted to use
  760.       // sstream when that is available.
  761.       ostrstream buf;
  762.  
  763.       int c = 0;
  764.       int count = 0;
  765.       int newline_stripped = 0;
  766.  
  767.       while (is && (c = is.get ()) != EOF)
  768.     {
  769.       count++;
  770.  
  771.       if (c == '\n')
  772.         {
  773.           if (! strip_newline)
  774.         buf << (char) c;
  775.           else
  776.         newline_stripped = 1;
  777.  
  778.           break;
  779.         }
  780.       else
  781.         buf << (char) c;
  782.  
  783.       if (max_len > 0 && count == max_len)
  784.         break;
  785.     }
  786.  
  787.       if (is.fail ())
  788.     {
  789.       err = true;
  790.       string msg = fcn;
  791.       msg.append (": read error");
  792.       error (msg);
  793.     }
  794.       else if (is.eof ())
  795.     {
  796.       err = true;
  797.       string msg = fcn;
  798.       msg.append (": at end of file");
  799.       error (msg);
  800.     }
  801.       else
  802.     {
  803.       buf << ends;
  804.       char *tmp = buf.str ();
  805.       retval = tmp;
  806.       delete [] tmp;
  807.     }
  808.     }
  809.   else
  810.     {
  811.       err = true;
  812.       invalid_operation (fcn, "reading");
  813.     }
  814.  
  815.   return retval;
  816. }
  817.  
  818. string
  819. octave_base_stream::getl (int max_len, bool& err)
  820. {
  821.   return do_gets (max_len, err, true, "fgetl");
  822. }
  823.  
  824. string
  825. octave_base_stream::gets (int max_len, bool& err)
  826. {
  827.   return do_gets (max_len, err, false, "fgets");
  828. }
  829.  
  830. octave_value
  831. octave_base_stream::read (const Matrix& size,
  832.               oct_data_conv::data_type dt, int skip,
  833.               oct_mach_info::float_format flt_fmt, int& count)
  834. {
  835.   Matrix retval;
  836.  
  837.   count = 0;
  838.  
  839.   istream *isp = input_stream ();
  840.  
  841.   if (isp)
  842.     {
  843.       istream& is = *isp;
  844.  
  845.       int nr = -1;
  846.       int nc = -1;
  847.  
  848.       get_size (size, nr, nc, "fread");
  849.  
  850.       if (! error_state)
  851.     {
  852.       if (flt_fmt == oct_mach_info::unknown)
  853.         flt_fmt = float_format ();
  854.  
  855.       int tmp = retval.read (is, nr, nc, dt, skip, flt_fmt);
  856.  
  857.       if (tmp < 0)
  858.         error ("fread: read error");
  859.       else
  860.         count = tmp;
  861.     }
  862.     }
  863.   else
  864.     invalid_operation ("fread", "reading");
  865.  
  866.   return retval;
  867. }
  868.  
  869. template <class T>
  870. void
  871. do_scanf_conv (istream& is, const char *fmt, T valptr, Matrix& mval,
  872.            double *data, int& idx, int nr, int max_size,
  873.            bool discard) 
  874. {
  875.   is.scan (fmt, valptr);
  876.  
  877.   if (is)
  878.     {
  879.       if (idx == max_size && ! discard)
  880.     {
  881.       max_size *= 2;
  882.  
  883.       if (nr > 0)
  884.         mval.resize (nr, max_size / nr, 0.0);
  885.       else
  886.         mval.resize (max_size, 1, 0.0);
  887.  
  888.       data = mval.fortran_vec ();
  889.     }
  890.  
  891.       if (! discard)
  892.     data[idx++] = *(valptr);
  893.     }
  894. }
  895.  
  896. template void
  897. do_scanf_conv (istream&, const char*, int*, Matrix&, double*, int&,
  898.            int, int, bool);
  899.  
  900. #if 0
  901. template void
  902. do_scanf_conv (istream&, const char*, float*, Matrix&, double*, int&,
  903.            int, int, bool);
  904. #endif
  905.  
  906. template void
  907. do_scanf_conv (istream&, const char*, double*, Matrix&, double*, int&,
  908.            int, int, bool);
  909.  
  910.  
  911. octave_value
  912. octave_base_stream::do_scanf (scanf_format_list& fmt_list,
  913.                   int nr, int nc, int& count)
  914. {
  915.   count = 0;
  916.  
  917.   octave_value retval = Matrix ();
  918.  
  919.   istream *isp = input_stream ();
  920.  
  921.   bool all_char_conv = fmt_list.all_character_conversions ();
  922.  
  923.   Matrix mval;
  924.   double *data = 0;
  925.   int max_size = 0;
  926.  
  927.   int final_nr = 0;
  928.   int final_nc = 0;
  929.  
  930.   if (nr > 0)
  931.     {
  932.       if (nc > 0)
  933.     {
  934.       mval.resize (nr, nc, 0.0);
  935.       data = mval.fortran_vec ();
  936.       max_size = nr * nc;
  937.     }
  938.       else
  939.     {
  940.       mval.resize (nr, 32, 0.0);
  941.       data = mval.fortran_vec ();
  942.       max_size = nr * 32;
  943.     }
  944.     }
  945.   else
  946.     {
  947.       mval.resize (32, 1, 0.0);
  948.       data = mval.fortran_vec ();
  949.       max_size = 32;
  950.     }
  951.  
  952.   if (isp)
  953.     {
  954.       istream& is = *isp;
  955.  
  956.       const scanf_format_elt *elt = fmt_list.first ();
  957.  
  958.       ios::fmtflags flags = is.flags ();
  959.  
  960.       for (;;)
  961.     {
  962.       if (elt)
  963.         {
  964.           if (count == max_size)
  965.         {
  966.           if (nr > 0)
  967.             {
  968.               if (nc > 0)
  969.             {
  970.               final_nr = nr;
  971.               final_nc = nc;
  972.  
  973.               break;
  974.             }
  975.               else
  976.             {
  977.               max_size *= 2;
  978.               mval.resize (nr, max_size / nr, 0.0);
  979.               data = mval.fortran_vec ();
  980.             }
  981.             }
  982.           else
  983.             {
  984.               max_size *=2;
  985.               mval.resize (max_size, 1, 0.0);
  986.               data = mval.fortran_vec ();
  987.             }
  988.         }
  989.  
  990.           const char *fmt = elt->text;
  991.  
  992.           bool discard = elt->discard;
  993.  
  994.           switch (elt->type)
  995.         {
  996.         case '%':
  997.           {
  998.             int dummy;
  999.  
  1000.             is.scan (fmt, &dummy);
  1001.           }
  1002.         break;
  1003.  
  1004.         case 'd': case 'i': case 'o': case 'u': case 'x':
  1005.           {
  1006.             int tmp;
  1007.  
  1008.             do_scanf_conv (is, fmt, &tmp, mval, data, count,
  1009.                    nr, max_size, discard);
  1010.           }
  1011.         break;
  1012.  
  1013.         case 'e': case 'f': case 'g':
  1014.           {
  1015.             double tmp;
  1016.  
  1017.             do_scanf_conv (is, fmt, &tmp, mval, data, count,
  1018.                    nr, max_size, discard);
  1019.           }
  1020.         break;
  1021.  
  1022.         case 'c':
  1023.           is.unsetf (ios::skipws);
  1024.           // Fall through...
  1025.  
  1026.         case 's':
  1027.           {
  1028.             int len = strlen (fmt);
  1029.             char *tmp_fmt = new char [len+1];
  1030.             strcpy (tmp_fmt, fmt);
  1031.             if (tmp_fmt[len-1] == 's')
  1032.               tmp_fmt[len-1] = 'c';
  1033.  
  1034.             int width = elt->width ? elt->width : 1;
  1035.  
  1036.             char *tmp = new char [width+1];
  1037.  
  1038.             is.scan (tmp_fmt, tmp);
  1039.  
  1040.             delete [] tmp_fmt;
  1041.  
  1042.             tmp[width] = '\0';
  1043.  
  1044.             if (is)
  1045.               {
  1046.             int i = 0;
  1047.  
  1048.             if (! discard)
  1049.               {
  1050.                 while (i < width && tmp[i] != '\0')
  1051.                   {
  1052.                 if (count == max_size)
  1053.                   {
  1054.                     max_size *= 2;
  1055.  
  1056.                     if (nr > 0)
  1057.                       mval.resize (nr, max_size / nr, 0.0);
  1058.                     else
  1059.                       mval.resize (max_size, 1, 0.0);
  1060.  
  1061.                     data = mval.fortran_vec ();
  1062.                   }
  1063.  
  1064.                 data[count++] = tmp[i++];
  1065.                   }
  1066.               }
  1067.               }
  1068.  
  1069.             delete [] tmp;
  1070.  
  1071.             is.setf (flags);
  1072.           }
  1073.         break;
  1074.  
  1075.         case 'p': case '[':
  1076.           error ("fscanf: unsupported format specifier");
  1077.           break;
  1078.  
  1079.         default:
  1080.           error ("fscanf: internal format error");
  1081.           break;
  1082.         }
  1083.  
  1084.           if (! ok ())
  1085.         {
  1086.           break;
  1087.         }
  1088.           else if (! is)
  1089.         {
  1090.           if (nr > 0)
  1091.             {
  1092.               if (count > nr)
  1093.             {
  1094.               final_nr = nr;
  1095.               final_nc = (count - 1) / nr + 1;
  1096.             }
  1097.               else
  1098.             {
  1099.               final_nr = count;
  1100.               final_nc = 1;
  1101.             }
  1102.             }
  1103.           else
  1104.             {
  1105.               final_nr = count;
  1106.               final_nc = 1;
  1107.             }
  1108.  
  1109.           // XXX FIXME XXX -- is this the right thing to do?
  1110.           // What about other streams?
  1111.           if (name () == "stdin")
  1112.             {
  1113.               is.clear ();
  1114.  
  1115.               // Skip to end of line.
  1116.  
  1117.               bool err;
  1118.               do_gets (-1, err, false, "fscanf");
  1119.             }
  1120.  
  1121.           break;
  1122.         }
  1123.         }
  1124.       else
  1125.         {
  1126.           error ("fscanf: internal format error");
  1127.           break;
  1128.         }
  1129.  
  1130.       elt = fmt_list.next ();
  1131.     }
  1132.     }
  1133.  
  1134.   if (ok ())
  1135.     {
  1136.       mval.resize (final_nr, final_nc, 0.0);
  1137.  
  1138.       if (all_char_conv)
  1139.     {
  1140.       if (nr < 0)
  1141.         mval = mval.transpose ();
  1142.  
  1143.       retval = mval;
  1144.  
  1145.       retval = retval.convert_to_str ();
  1146.     }
  1147.       else
  1148.     retval = mval;
  1149.     }
  1150.  
  1151.   return retval;
  1152. }
  1153.  
  1154. octave_value
  1155. octave_base_stream::scanf (const string& fmt, const Matrix& size,
  1156.                int& count)
  1157. {
  1158.   octave_value retval = Matrix ();
  1159.  
  1160.   count = 0;
  1161.  
  1162.   istream *isp = input_stream ();
  1163.  
  1164.   if (isp)
  1165.     {
  1166.       istream& is = *isp;
  1167.  
  1168.       scanf_format_list fmt_list (fmt);
  1169.  
  1170.       switch (fmt_list.num_conversions ())
  1171.     {
  1172.     case -1:
  1173.       ::error ("fscanf: invalid format specified");
  1174.       break;
  1175.  
  1176.     case 0:
  1177.       {
  1178.         const scanf_format_elt *elt = fmt_list.first ();
  1179.  
  1180.         if (elt)
  1181.           {
  1182.         is.clear ();
  1183.  
  1184.         is.scan (elt->text);
  1185.  
  1186.         if (! is)
  1187.           {
  1188.             error ("fscanf: read error");
  1189.  
  1190.             // XXX FIXME XXX -- is this the right thing to do?
  1191.  
  1192.             if (name () == "stdin")
  1193.               {
  1194.             is.clear ();
  1195.  
  1196.             // Skip to end of line.
  1197.  
  1198.             bool err;
  1199.             do_gets (-1, err, false, "fscanf");
  1200.               }
  1201.           }
  1202.           }
  1203.       }
  1204.       break;
  1205.  
  1206.     default:
  1207.       {
  1208.         int nr = -1;
  1209.         int nc = -1;
  1210.  
  1211.         get_size (size, nr, nc, "fscanf");
  1212.  
  1213.         if (! error_state)
  1214.           retval = do_scanf (fmt_list, nr, nc, count);
  1215.       }
  1216.       break;
  1217.     }
  1218.     }
  1219.   else
  1220.     invalid_operation ("fscanf", "reading");
  1221.  
  1222.   return retval;
  1223. }
  1224.  
  1225. bool
  1226. octave_base_stream::do_oscanf (const scanf_format_elt *elt,
  1227.                    octave_value& retval)
  1228. {
  1229.   bool quit = false;
  1230.  
  1231.   istream *isp = input_stream ();
  1232.  
  1233.   if (isp)
  1234.     {
  1235.       istream& is = *isp;
  1236.  
  1237.       ios::fmtflags flags = is.flags ();
  1238.  
  1239.       if (elt)
  1240.     {
  1241.       const char *fmt = elt->text;
  1242.  
  1243.       bool discard = elt->discard;
  1244.  
  1245.       switch (elt->type)
  1246.         {
  1247.         case '%':
  1248.           {
  1249.         int dummy;
  1250.  
  1251.         if (! is.scan (fmt, &dummy))
  1252.           quit = true;
  1253.           }
  1254.           break;
  1255.  
  1256.         case 'd': case 'i': case 'o': case 'u': case 'x':
  1257.           {
  1258.         int tmp;
  1259.  
  1260.         if (is.scan (fmt, &tmp))
  1261.           {
  1262.             if (! discard)
  1263.               retval = (double) tmp;
  1264.           }
  1265.         else
  1266.           quit = true;
  1267.           }
  1268.           break;
  1269.  
  1270.         case 'e': case 'f': case 'g':
  1271.           {
  1272.         double tmp;
  1273.  
  1274.         if (is.scan (fmt, &tmp))
  1275.           {
  1276.             if (! discard)
  1277.               retval = tmp;
  1278.           }
  1279.         else
  1280.           quit = true;
  1281.           }
  1282.           break;
  1283.  
  1284.         case 'c':
  1285.           {
  1286.         is.unsetf (ios::skipws);
  1287.  
  1288.         int width = elt->width ? elt->width : 1;
  1289.  
  1290.         char *tmp = new char[width + 1];
  1291.  
  1292.         if (is.scan (fmt, tmp))
  1293.           {
  1294.             if (! discard)
  1295.               {
  1296.             tmp[width] = '\0';
  1297.             retval = tmp;
  1298.               }
  1299.           }
  1300.         else
  1301.           quit = true;
  1302.  
  1303.         is.setf (flags);
  1304.  
  1305.         delete [] tmp;
  1306.           }
  1307.           break;
  1308.  
  1309.         case 's':
  1310.           {
  1311.         // XXX FIXME XXX -- this must be fixed!
  1312.  
  1313.         int width = elt->width ? elt->width : 65535;
  1314.         char *tmp = new char [width+1];
  1315.  
  1316.         if (is.scan (fmt, tmp))
  1317.           {
  1318.             if (! discard)
  1319.               {
  1320.             tmp[width] = '\0';
  1321.             retval = tmp;
  1322.               }
  1323.           }
  1324.         else
  1325.           quit = true;
  1326.  
  1327.         delete [] tmp;
  1328.           }
  1329.           break;
  1330.  
  1331.         case 'p': case '[':
  1332.           error ("fscanf: unsupported format specifier");
  1333.           break;
  1334.  
  1335.         default:
  1336.           error ("fscanf: internal format error");
  1337.           break;
  1338.         }
  1339.     }
  1340.  
  1341.       if (ok () && is.fail ())
  1342.     {
  1343.       error ("fscanf: read error");
  1344.       
  1345.       // XXX FIXME XXX -- is this the right thing to do?
  1346.       // What about other streams?
  1347.       if (name () == "stdin")
  1348.         {
  1349.           is.clear ();
  1350.  
  1351.           // Skip to end of line.
  1352.  
  1353.           bool err;
  1354.           do_gets (-1, err, false, "fscanf");
  1355.         }
  1356.     }
  1357.     }
  1358.  
  1359.   return quit;
  1360. }
  1361.  
  1362. octave_value_list
  1363. octave_base_stream::oscanf (const string& fmt)
  1364. {
  1365.   octave_value_list retval;
  1366.  
  1367.   istream *isp = input_stream ();
  1368.  
  1369.   if (isp)
  1370.     {
  1371.       istream& is = *isp;
  1372.  
  1373.       scanf_format_list fmt_list (fmt);
  1374.  
  1375.       int nconv = fmt_list.num_conversions ();
  1376.  
  1377.       switch (nconv)
  1378.     {
  1379.     case -1:
  1380.       ::error ("fscanf: invalid format specified");
  1381.       break;
  1382.  
  1383.     case 0:
  1384.       {
  1385.         const scanf_format_elt *elt = fmt_list.first ();
  1386.  
  1387.         if (elt)
  1388.           {
  1389.         is.clear ();
  1390.  
  1391.         is.scan (elt->text);
  1392.  
  1393.         if (! is)
  1394.           {
  1395.             error ("fscanf: read error");
  1396.  
  1397.             // XXX FIXME XXX -- is this the right thing to do?
  1398.             // Maybe.  We should probably also arrange to
  1399.             // flush the pending input prior to printing a
  1400.             // prompt.  Or maybe just blow off scanf for stdin
  1401.             // like the MathWorks did. What about other streams?
  1402.  
  1403.             if (name () == "stdin")
  1404.               {
  1405.             is.clear ();
  1406.  
  1407.             // Skip to end of line.
  1408.  
  1409.             bool err;
  1410.             do_gets (-1, err, false, "fscanf");
  1411.               }
  1412.           }
  1413.           }
  1414.       }
  1415.       break;
  1416.  
  1417.     default:
  1418.       {
  1419.         int len = fmt_list.length ();
  1420.  
  1421.         retval.resize (nconv, Matrix ());
  1422.  
  1423.         const scanf_format_elt *elt = fmt_list.first ();
  1424.  
  1425.         int num_values = 0;
  1426.  
  1427.         bool quit = false;
  1428.  
  1429.         for (int i = 0; i < nconv; i++)
  1430.           {
  1431.         octave_value tmp;
  1432.  
  1433.         quit = do_oscanf (elt, tmp);
  1434.  
  1435.         if (quit)
  1436.           break;
  1437.         else
  1438.           {
  1439.             if (tmp.is_defined ())
  1440.               retval (num_values++) = tmp;
  1441.  
  1442.             if (! ok ())
  1443.               break;
  1444.             elt = fmt_list.next ();
  1445.           }
  1446.           }
  1447.  
  1448.         retval.resize (num_values);
  1449.  
  1450.         if (! quit)
  1451.           {
  1452.         // Pick up any trailing stuff.
  1453.         if (ok () && len > nconv)
  1454.           {
  1455.             octave_value tmp;
  1456.             do_oscanf (elt, tmp);
  1457.           }
  1458.           }
  1459.       }
  1460.       break;
  1461.     }
  1462.     }
  1463.   else
  1464.     invalid_operation ("fscanf", "reading");
  1465.  
  1466.   return retval;
  1467. }
  1468.  
  1469. // Functions that are defined for all output streams (output streams
  1470. // are those that define os).
  1471.  
  1472. int
  1473. octave_base_stream::flush (void)
  1474. {
  1475.   int retval = -1;
  1476.  
  1477.   ostream *os = output_stream ();
  1478.  
  1479.   if (os)
  1480.     {
  1481.       os->flush ();
  1482.  
  1483.       if (os->good ())
  1484.     retval = 0;
  1485.     }
  1486.   else
  1487.     invalid_operation ("fflush", "writing");
  1488.  
  1489.   return retval;
  1490. }
  1491.  
  1492. int
  1493. octave_base_stream::write (const octave_value& data,
  1494.                oct_data_conv::data_type dt, int skip,
  1495.                oct_mach_info::float_format flt_fmt)
  1496. {
  1497.   int retval = -1;
  1498.  
  1499.   ostream *osp = output_stream ();
  1500.  
  1501.   if (osp)
  1502.     {
  1503.       ostream& os = *osp;
  1504.  
  1505.       Matrix mval = data.matrix_value ();
  1506.  
  1507.       if (! error_state)
  1508.     {
  1509.       if (flt_fmt == oct_mach_info::unknown)
  1510.         flt_fmt = float_format ();
  1511.  
  1512.       int tmp = mval.write (os, dt, skip, flt_fmt);
  1513.  
  1514.       if (tmp < 0)
  1515.         error ("fwrite: write error");
  1516.       else
  1517.         retval = tmp;
  1518.     }
  1519.     }
  1520.   else
  1521.     invalid_operation ("fwrite", "writing");
  1522.  
  1523.   return retval;
  1524. }
  1525.  
  1526. class
  1527. printf_value_cache
  1528. {
  1529. public:
  1530.  
  1531.   enum state { ok, list_exhausted, conversion_error };
  1532.  
  1533.   printf_value_cache (const octave_value_list& args)
  1534.     : values (args), val_idx (0), elt_idx (0),
  1535.       n_vals (values.length ()), n_elts (0), data (0),
  1536.       curr_state (ok) { }
  1537.  
  1538.   ~printf_value_cache (void) { }
  1539.  
  1540.   // Get the current value as a double and advance the internal pointer.
  1541.   double double_value (void);
  1542.  
  1543.   // Get the current value as an int and advance the internal pointer.
  1544.   int int_value (void);
  1545.  
  1546.   // Get the current value as a string and advance the internal pointer.
  1547.   string string_value (void);
  1548.  
  1549.   operator void* () const
  1550.     { return (curr_state == ok) ? (void *) -1 : (void *) 0; }
  1551.  
  1552.   bool no_more_values (void) { return curr_state == list_exhausted; }
  1553.  
  1554.   bool looking_at_string (void);
  1555.  
  1556. private:
  1557.  
  1558.   const octave_value_list values;
  1559.   int val_idx;
  1560.   int elt_idx;
  1561.   int n_vals;
  1562.   int n_elts;
  1563.   const double *data;
  1564.   Matrix curr_val;
  1565.   state curr_state;
  1566.  
  1567.   // Must create value cache with values!
  1568.  
  1569.   printf_value_cache (void);
  1570.  
  1571.   // No copying!
  1572.  
  1573.   printf_value_cache (const printf_value_cache&);
  1574.  
  1575.   printf_value_cache& operator = (const printf_value_cache&);
  1576. };
  1577.  
  1578. bool
  1579. printf_value_cache::looking_at_string (void)
  1580. {
  1581.   bool retval = false;
  1582.  
  1583.   int idx = -1;
  1584.  
  1585.   if (elt_idx == 0)
  1586.     idx = val_idx;
  1587.   else if (elt_idx >= n_elts)
  1588.     idx = val_idx + 1;
  1589.  
  1590.   if (idx >= 0 && idx < n_vals)
  1591.     {
  1592.       octave_value tmp_val = values (idx);
  1593.  
  1594.       // An empty string has zero rows and zero columns.
  1595.  
  1596.       if (tmp_val.is_string ())
  1597.     {
  1598.       int nr = tmp_val.rows ();
  1599.  
  1600.       retval = (nr == 1 || (nr == 0 && tmp_val.columns () == 0));
  1601.     }
  1602.     }
  1603.  
  1604.   return retval;
  1605. }
  1606.  
  1607. double
  1608. printf_value_cache::double_value (void)
  1609. {
  1610.   double retval = 0.0;
  1611.  
  1612.   while (val_idx < n_vals)
  1613.     {
  1614.       if (! data)
  1615.     {
  1616.       octave_value tmp_val = values (val_idx);
  1617.  
  1618.       curr_val = tmp_val.matrix_value ();
  1619.  
  1620.       if (! error_state)
  1621.         {
  1622.           elt_idx = 0;
  1623.           n_elts = curr_val.length ();
  1624.           data = curr_val.data ();
  1625.         }
  1626.       else
  1627.         {
  1628.           curr_state = conversion_error;
  1629.           break;
  1630.         }
  1631.     }
  1632.  
  1633.       if (elt_idx < n_elts)
  1634.     {
  1635.       return data[elt_idx++];
  1636.       break;
  1637.     }
  1638.       else
  1639.     {
  1640.       val_idx++;
  1641.       data = 0;
  1642.       continue;
  1643.     }
  1644.     }
  1645.  
  1646.   curr_state = list_exhausted;
  1647.  
  1648.   return retval;
  1649. }
  1650.  
  1651. int
  1652. printf_value_cache::int_value (void)
  1653. {
  1654.   int retval = 0;
  1655.  
  1656.   double dval = double_value ();
  1657.  
  1658.   if (! error_state)
  1659.     {
  1660.       if (D_NINT (dval) == dval)
  1661.     retval = NINT (dval);
  1662.       else
  1663.     curr_state = conversion_error;
  1664.     }
  1665.  
  1666.   return retval;
  1667. }
  1668.  
  1669. string
  1670. printf_value_cache::string_value (void)
  1671. {
  1672.   string retval;
  1673.  
  1674.   if (looking_at_string ())
  1675.     {
  1676.       if (elt_idx != 0)
  1677.     {
  1678.       val_idx++;
  1679.       elt_idx = 0;
  1680.       data = 0;
  1681.     }
  1682.  
  1683.       retval = values (val_idx++).string_value ();
  1684.     }
  1685.   else
  1686.     curr_state = conversion_error;
  1687.  
  1688.   return retval;
  1689. }
  1690.  
  1691. // Ugh again and again.
  1692.  
  1693. template <class T>
  1694. void
  1695. do_printf_conv (ostream& os, const char *fmt, int nsa, int sa_1,
  1696.         int sa_2, bool have_arg, T arg)
  1697. {
  1698.   switch (nsa)
  1699.     {
  1700.     case 2:
  1701.       if (have_arg)
  1702.     os.form (fmt, sa_1, sa_2, arg);
  1703.       else
  1704.     os.form (fmt, sa_1, sa_2);
  1705.       break;
  1706.  
  1707.     case 1:
  1708.       if (have_arg)
  1709.     os.form (fmt, sa_1, arg);
  1710.       else
  1711.     os.form (fmt, sa_1);
  1712.       break;
  1713.  
  1714.     case 0:
  1715.       if (have_arg)
  1716.     os.form (fmt, arg);
  1717.       else
  1718.     os.form (fmt);
  1719.       break;
  1720.  
  1721.     default:
  1722.       ::error ("fprintf: internal error handling format");
  1723.       break;
  1724.     }
  1725. }
  1726.  
  1727. template void
  1728. do_printf_conv (ostream&, const char*, int, int, int, bool, int);
  1729.  
  1730. template void
  1731. do_printf_conv (ostream&, const char*, int, int, int, bool, long);
  1732.  
  1733. template void
  1734. do_printf_conv (ostream&, const char*, int, int, int, bool, double);
  1735.  
  1736. template void
  1737. do_printf_conv (ostream&, const char*, int, int, int, bool, const char*);
  1738.  
  1739. int
  1740. octave_base_stream::do_printf (printf_format_list& fmt_list,
  1741.                    const octave_value_list& args)
  1742. {
  1743.   int retval = -1;
  1744.  
  1745.   ostream *osp = output_stream ();
  1746.  
  1747.   if (osp)
  1748.     {
  1749.       ostream& os = *osp;
  1750.  
  1751.       const printf_format_elt *elt = fmt_list.first ();
  1752.  
  1753.       printf_value_cache val_cache (args);
  1754.  
  1755.       for (;;)
  1756.     {
  1757.       if (elt)
  1758.         {
  1759.           int args = elt->args;
  1760.           int nsa = args;
  1761.  
  1762.           int doing_percent = elt->type == '%';
  1763.  
  1764.           if (args > 0 && ! doing_percent)
  1765.         nsa--;
  1766.  
  1767.           int sa_1 = 0;
  1768.           int sa_2 = 0; 
  1769.  
  1770.           if (nsa > 0)
  1771.         {
  1772.           sa_1 = val_cache.int_value ();
  1773.  
  1774.           if (! val_cache)
  1775.             break;
  1776.           else
  1777.             {
  1778.               if (nsa > 1)
  1779.             {
  1780.               sa_2 = val_cache.int_value ();
  1781.  
  1782.               if (! val_cache)
  1783.                 break;
  1784.             }
  1785.             }
  1786.         }
  1787.  
  1788.           const char *fmt = elt->text;
  1789.  
  1790.           if (doing_percent || args == 0)
  1791.         do_printf_conv (os, fmt, nsa, sa_1, sa_2, false, 0.0);
  1792.           else
  1793.         {
  1794.           if (elt->type == 's' && val_cache.looking_at_string ())
  1795.             {
  1796.               string val = val_cache.string_value ();
  1797.  
  1798.               if (val_cache)
  1799.             do_printf_conv (os, fmt, nsa, sa_1, sa_2, true,
  1800.                     val.c_str ());
  1801.               else
  1802.             break;
  1803.             }
  1804.           else
  1805.             {
  1806.               double val = val_cache.double_value ();
  1807.  
  1808.               if (val_cache)
  1809.             {
  1810.               switch (elt->type)
  1811.                 {
  1812.                 case 'd': case 'i': case 'o': case 'x':
  1813.                 case 'X': case 'u': case 'c':
  1814.                   {
  1815.                 if (elt->modifier == 'l')
  1816.                   do_printf_conv (os, fmt, nsa, sa_1,
  1817.                           sa_2, true, (long) val);
  1818.                 else
  1819.                   do_printf_conv (os, fmt, nsa, sa_1,
  1820.                           sa_2, true, (int) val);
  1821.                   }
  1822.                   break;
  1823.  
  1824.                 case 'f': case 'e': case 'E':
  1825.                 case 'g': case 'G':
  1826.                   do_printf_conv (os, fmt, nsa, sa_1,
  1827.                           sa_2, true, val);
  1828.                   break;
  1829.  
  1830.                 default:
  1831.                   error ("fprintf: invalid format specifier");
  1832.                   return -1;
  1833.                   break;
  1834.                 }
  1835.             }
  1836.               else
  1837.             break;
  1838.             }
  1839.  
  1840.           if (val_cache.no_more_values ())
  1841.             {
  1842.               retval = 0;
  1843.               break;
  1844.             }
  1845.         }
  1846.  
  1847.           if (os)
  1848.         retval += nsa + (doing_percent ? 0 : 1);
  1849.           else
  1850.         {
  1851.           error ("fprintf: write error");
  1852.           retval = -1;
  1853.           break;
  1854.         }
  1855.         }
  1856.       else
  1857.         {
  1858.           ::error ("fprintf: internal error handling format");
  1859.           retval = -1;
  1860.           break;
  1861.         }
  1862.  
  1863.       elt = fmt_list.next ();
  1864.     }
  1865.     }
  1866.  
  1867.   return retval;
  1868. }
  1869.  
  1870. int
  1871. octave_base_stream::printf (const string& fmt, const octave_value_list& args)
  1872. {
  1873.   int retval = -1;
  1874.  
  1875.   ostream *osp = output_stream ();
  1876.  
  1877.   if (osp)
  1878.     {
  1879.       ostream& os = *osp;
  1880.  
  1881.       printf_format_list fmt_list (fmt);
  1882.  
  1883.       switch (fmt_list.num_conversions ())
  1884.     {
  1885.     case -1:
  1886.       ::error ("fprintf: invalid format specified");
  1887.       break;
  1888.  
  1889.     case 0:
  1890.       {
  1891.         const printf_format_elt *elt = fmt_list.first ();
  1892.  
  1893.         if (elt)
  1894.           {
  1895.         os.form (elt->text);
  1896.  
  1897.         if (os)
  1898.           retval = 0;
  1899.         else
  1900.           error ("fprintf: write error");
  1901.           }
  1902.       }
  1903.       break;
  1904.  
  1905.     default:
  1906.       {
  1907.         if (args.length () == 0)
  1908.           ::error ("fprintf: no arguments available for specified format");
  1909.         else
  1910.           retval = do_printf (fmt_list, args);
  1911.       }
  1912.       break;
  1913.     }
  1914.     }
  1915.   else
  1916.     invalid_operation ("fprintf", "writing");
  1917.  
  1918.   return retval;
  1919. }
  1920.  
  1921. int
  1922. octave_base_stream::puts (const string& s)
  1923. {
  1924.   int retval = -1;
  1925.  
  1926.   ostream *osp = output_stream ();
  1927.  
  1928.   if (osp)
  1929.     {
  1930.       ostream& os = *osp;
  1931.  
  1932.       os << s;
  1933.  
  1934.       if (os)
  1935.     {
  1936.       // XXX FIXME XXX -- why does this seem to be necessary?
  1937.       // Without it, output from a loop like
  1938.       //
  1939.       //   for i = 1:100, fputs (stdout, "foo\n"); endfor
  1940.       //
  1941.       // doesn't seem to go to the pager immediately.
  1942.  
  1943.       os.flush ();
  1944.  
  1945.       if (os)
  1946.         retval = 0;
  1947.       else
  1948.         error ("fputs: write error");
  1949.     }
  1950.       else
  1951.     error ("fputs: write error");
  1952.     }
  1953.   else
  1954.     invalid_operation ("fputs", "writing");
  1955.  
  1956.   return retval;
  1957. }
  1958.  
  1959. int
  1960. octave_base_stream::rewind (void)
  1961. {
  1962.   return seek (0, ios::beg);
  1963. }
  1964.  
  1965. // Return current error message for this stream.
  1966.  
  1967. string
  1968. octave_base_stream::error (bool clear_err, int& err_num)
  1969. {
  1970.   err_num = fail ? -1 : 0;
  1971.  
  1972.   string tmp = errmsg;
  1973.  
  1974.   if (clear_err)
  1975.     clear ();
  1976.  
  1977.   return tmp;
  1978. }
  1979.  
  1980. void
  1981. octave_base_stream::invalid_operation (const char *op, const char *rw)
  1982. {
  1983.   string msg = op;
  1984.   msg.append (": stream not open for ");
  1985.   msg.append (rw);
  1986.   error (msg);
  1987. }
  1988.  
  1989. int
  1990. octave_stream::flush (void)
  1991. {
  1992.   int retval = -1;
  1993.  
  1994.   if (stream_ok ("fflush"))
  1995.     retval = rep->flush ();
  1996.  
  1997.   return retval;
  1998. }
  1999.  
  2000. string
  2001. octave_stream::getl (int max_len, bool& err)
  2002. {
  2003.   string retval;
  2004.  
  2005.   if (stream_ok ("getl"))
  2006.     retval = rep->getl (max_len, err);
  2007.  
  2008.   return retval;
  2009. }
  2010.  
  2011. string
  2012. octave_stream::getl (const octave_value& tc_max_len, bool& err)
  2013. {
  2014.   string retval;
  2015.  
  2016.   err = false;
  2017.  
  2018.   int conv_err = 0;
  2019.  
  2020.   int max_len = convert_to_valid_int (tc_max_len, conv_err);
  2021.  
  2022.   if (conv_err || max_len < 0)
  2023.     {
  2024.       err = true;
  2025.       ::error ("fgetl: invalid maximum length specified");
  2026.     }
  2027.   else
  2028.     retval = getl (max_len, err);
  2029.  
  2030.   return retval;
  2031. }
  2032.  
  2033. string
  2034. octave_stream::gets (int max_len, bool& err)
  2035. {
  2036.   string retval;
  2037.  
  2038.   if (stream_ok ("fgets"))
  2039.     retval = rep->gets (max_len, err);
  2040.  
  2041.   return retval;
  2042. }
  2043.  
  2044. string
  2045. octave_stream::gets (const octave_value& tc_max_len, bool& err)
  2046. {
  2047.   string retval;
  2048.  
  2049.   err = false;
  2050.  
  2051.   int conv_err = 0;
  2052.  
  2053.   int max_len = convert_to_valid_int (tc_max_len, conv_err);
  2054.  
  2055.   if (conv_err || max_len < 0)
  2056.     {
  2057.       err = true;
  2058.       ::error ("fgets: invalid maximum length specified");
  2059.     }
  2060.   else
  2061.     retval = gets (max_len, err);
  2062.  
  2063.   return retval;
  2064. }
  2065.  
  2066. int
  2067. octave_stream::seek (streamoff offset, ios::seek_dir origin)
  2068. {
  2069.   int retval = -1;
  2070.  
  2071.   if (stream_ok ("fseek"))
  2072.     retval = rep->seek (offset, origin);
  2073.  
  2074.   return retval;
  2075. }
  2076.  
  2077. int
  2078. octave_stream::seek (const octave_value& tc_offset,
  2079.              const octave_value& tc_origin)
  2080. {
  2081.   int retval = -1;
  2082.  
  2083.   int conv_err = 0;
  2084.  
  2085.   int xoffset = convert_to_valid_int (tc_offset, conv_err);
  2086.  
  2087.   if (! conv_err)
  2088.     {
  2089.       ios::seek_dir origin = ios::beg;
  2090.  
  2091.       if (tc_origin.is_string ())
  2092.     {
  2093.       string xorigin = tc_origin.string_value ();
  2094.  
  2095.       if (xorigin == "bof")
  2096.         origin = ios::beg;
  2097.       else if (xorigin == "cof")
  2098.         origin = ios::cur;
  2099.       else if (xorigin == "eof")
  2100.         origin = ios::end;
  2101.       else
  2102.         conv_err = -1;
  2103.     }
  2104.       else
  2105.     {
  2106.       int xorigin = convert_to_valid_int (tc_origin, conv_err);
  2107.  
  2108.       if (! conv_err)
  2109.         {
  2110.           if (xorigin == -1)
  2111.         origin = ios::beg;
  2112.           else if (xorigin == 0)
  2113.         origin = ios::cur;
  2114.           else if (xorigin == 1)
  2115.         origin = ios::end;
  2116.           else
  2117.         conv_err = -1;
  2118.         }
  2119.     }
  2120.  
  2121.       if (! conv_err)
  2122.     retval = seek (xoffset, origin);
  2123.       else
  2124.     error ("fseek: invalid value for origin");
  2125.     }
  2126.   else
  2127.     error ("fseek: invalid value for offset");
  2128.  
  2129.   return retval;
  2130. }
  2131.  
  2132. long
  2133. octave_stream::tell (void) const
  2134. {
  2135.   long retval = -1;
  2136.  
  2137.   if (stream_ok ("tell"))
  2138.     retval = rep->tell ();
  2139.  
  2140.   return retval;
  2141. }
  2142.  
  2143. int
  2144. octave_stream::rewind (void)
  2145. {
  2146.   int retval = -1;
  2147.  
  2148.   if (stream_ok ("frewind"))
  2149.     retval = rep->rewind ();
  2150.  
  2151.   return retval;
  2152. }
  2153.  
  2154. octave_value
  2155. octave_stream::read (const Matrix& size,
  2156.              oct_data_conv::data_type dt, int skip,
  2157.              oct_mach_info::float_format flt_fmt, int& count)
  2158. {
  2159.   octave_value retval;
  2160.  
  2161.   if (stream_ok ("fread"))
  2162.     retval = rep->read (size, dt, skip, flt_fmt, count);
  2163.  
  2164.   return retval;
  2165. }
  2166.  
  2167. int
  2168. octave_stream::write (const octave_value& data,
  2169.               oct_data_conv::data_type dt, int skip,
  2170.               oct_mach_info::float_format flt_fmt)
  2171. {
  2172.   int retval = -1;
  2173.  
  2174.   if (stream_ok ("fwrite"))
  2175.     retval = rep->write (data, dt, skip, flt_fmt);
  2176.  
  2177.   return retval;
  2178. }
  2179.  
  2180. octave_value
  2181. octave_stream::scanf (const string& fmt, const Matrix& size, int& count)
  2182. {
  2183.   octave_value retval;
  2184.  
  2185.   if (stream_ok ("fscanf"))
  2186.     retval = rep->scanf (fmt, size, count);
  2187.  
  2188.   return retval;
  2189. }
  2190.  
  2191. octave_value_list
  2192. octave_stream::oscanf (const string& fmt)
  2193. {
  2194.   octave_value_list retval;
  2195.  
  2196.   if (stream_ok ("fscanf"))
  2197.     retval = rep->oscanf (fmt);
  2198.  
  2199.   return retval;
  2200. }
  2201.  
  2202. int
  2203. octave_stream::printf (const string& fmt, const octave_value_list& args)
  2204. {
  2205.   int retval = -1;
  2206.  
  2207.   if (stream_ok ("fprintf"))
  2208.     retval = rep->printf (fmt, args);
  2209.  
  2210.   return retval;
  2211. }
  2212.  
  2213. int
  2214. octave_stream::puts (const string& s)
  2215. {
  2216.   int retval = -1;
  2217.  
  2218.   if (stream_ok ("fputs"))
  2219.     retval = rep->puts (s);
  2220.  
  2221.   return retval;
  2222. }
  2223.  
  2224. // XXX FIXME XXX -- maybe this should work for string arrays too.
  2225.  
  2226. int
  2227. octave_stream::puts (const octave_value& tc_s)
  2228. {
  2229.   int retval = -1;
  2230.  
  2231.   if (tc_s.is_string ())
  2232.     {
  2233.       string s = tc_s.string_value ();      
  2234.       retval = rep->puts (s);
  2235.     }
  2236.   else
  2237.     error ("fputs: argument must be a string");
  2238.  
  2239.   return retval;
  2240. }
  2241.  
  2242. bool
  2243. octave_stream::eof (void) const
  2244. {
  2245.   int retval = -1;
  2246.  
  2247.   if (stream_ok ("feof"))
  2248.     retval = rep->eof ();
  2249.  
  2250.   return retval;
  2251. }
  2252.  
  2253. string
  2254. octave_stream::error (bool clear, int& err_num)
  2255. {
  2256.   string retval;
  2257.  
  2258.   if (stream_ok ("ferror", false))
  2259.     retval = rep->error (clear, err_num);
  2260.  
  2261.   return retval;
  2262. }
  2263.  
  2264. string
  2265. octave_stream::name (void)
  2266. {
  2267.   string retval;
  2268.  
  2269.   if (stream_ok ("name"))
  2270.     retval = rep->name ();
  2271.  
  2272.   return retval;
  2273. }
  2274.  
  2275. int
  2276. octave_stream::mode (void)
  2277. {
  2278.   int retval = 0;
  2279.  
  2280.   if (stream_ok ("mode"))
  2281.     retval = rep->mode ();
  2282.  
  2283.   return retval;
  2284. }
  2285.  
  2286. oct_mach_info::float_format
  2287. octave_stream::float_format (void)
  2288. {
  2289.   oct_mach_info::float_format retval = oct_mach_info::unknown;
  2290.  
  2291.   if (stream_ok ("float_format"))
  2292.     retval = rep->float_format ();
  2293.  
  2294.   return retval;
  2295. }
  2296.  
  2297. string
  2298. octave_stream::mode_as_string (int mode)
  2299. {
  2300.   string retval = "???";
  2301.  
  2302.   switch (mode)
  2303.     {
  2304.     case ios::in:
  2305.       retval = "r";
  2306.       break;
  2307.  
  2308.     case ios::out:
  2309.     case ios::out | ios::trunc:
  2310.       retval = "w";
  2311.       break;
  2312.  
  2313.     case ios::out | ios::app:
  2314.       retval = "a";
  2315.       break;
  2316.  
  2317.     case ios::in | ios::out:
  2318.       retval = "r+";
  2319.       break;
  2320.  
  2321.     case ios::in | ios::out | ios::trunc:
  2322.       retval = "w+";
  2323.       break;
  2324.  
  2325.     case ios::in | ios::out | ios::app:
  2326.       retval = "a+";
  2327.       break;
  2328.  
  2329.     case ios::in | ios::bin:
  2330.       retval = "rb";
  2331.       break;
  2332.  
  2333.     case ios::out | ios::bin:
  2334.     case ios::out | ios::trunc | ios::bin:
  2335.       retval = "wb";
  2336.       break;
  2337.  
  2338.     case ios::out | ios::app | ios::bin:
  2339.       retval = "ab";
  2340.       break;
  2341.  
  2342.     case ios::in | ios::out | ios::bin:
  2343.       retval = "r+b";
  2344.       break;
  2345.  
  2346.     case ios::in | ios::out | ios::trunc | ios::bin:
  2347.       retval = "w+b";
  2348.       break;
  2349.  
  2350.     case ios::in | ios::out | ios::app | ios::bin:
  2351.       retval = "a+b";
  2352.       break;
  2353.  
  2354.     default:
  2355.       break;
  2356.     }
  2357.  
  2358.   return retval;
  2359. }
  2360.  
  2361. void
  2362. octave_stream::invalid_stream_error (const char *op) const
  2363. {
  2364.   ::error ("%s: attempt to use invalid I/O stream", op);
  2365. }
  2366.  
  2367. octave_stream_list *octave_stream_list::instance = 0;
  2368.  
  2369. int
  2370. octave_stream_list::do_insert (octave_base_stream *obs)
  2371. {
  2372.   int retval = -1;
  2373.  
  2374.   if (obs)
  2375.     {
  2376.       octave_stream *os = new octave_stream (obs);
  2377.  
  2378.       // Insert item in first open slot, increasing size of list if
  2379.       // necessary.
  2380.  
  2381.       for (int i = 0; i < curr_len; i++)
  2382.     {
  2383.       octave_stream *tmp = list (i);
  2384.  
  2385.       if (! tmp)
  2386.         {
  2387.           list (i) = os;
  2388.           retval = i;
  2389.           break;
  2390.         }
  2391.     }
  2392.  
  2393.       if (retval < 0)
  2394.     {
  2395.       int total_len = list.length ();
  2396.  
  2397.       if (curr_len == total_len)
  2398.         list.resize (total_len * 2);
  2399.  
  2400.       list (curr_len) = os;
  2401.       retval = curr_len;
  2402.       curr_len++;
  2403.     }
  2404.     }
  2405.   else
  2406.     ::error ("octave_stream_list: attempt to insert invalid stream");
  2407.  
  2408.   return retval;
  2409. }
  2410.  
  2411. int
  2412. octave_stream_list::insert (octave_base_stream *obs)
  2413. {
  2414.   int retval = -1;
  2415.  
  2416.   if (! instance)
  2417.     instance = new octave_stream_list ();
  2418.  
  2419.   if (instance)
  2420.     retval = instance->do_insert (obs);
  2421.   else
  2422.     panic_impossible ();
  2423.  
  2424.   return retval;
  2425. }
  2426.  
  2427. octave_stream *
  2428. octave_stream_list::do_lookup (int fid) const
  2429. {
  2430.   octave_stream *retval = 0;
  2431.  
  2432.   if (fid >= 0 && fid < curr_len)
  2433.     retval = list (fid);
  2434.  
  2435.   return retval;
  2436. }
  2437.  
  2438. octave_stream *
  2439. octave_stream_list::do_lookup (const octave_value& fid) const
  2440. {
  2441.   octave_stream *retval = 0;
  2442.  
  2443.   int i = get_file_number (fid);
  2444.  
  2445.   if (! error_state)
  2446.     retval = do_lookup (i);
  2447.  
  2448.   return retval;
  2449. }
  2450.  
  2451. octave_stream *
  2452. octave_stream_list::lookup (int fid)
  2453. {
  2454.   octave_stream *retval = 0;
  2455.  
  2456.   if (instance)
  2457.     retval = instance->do_lookup (fid);
  2458.  
  2459.   return retval;
  2460. }
  2461.  
  2462. octave_stream *
  2463. octave_stream_list::lookup (const octave_value& fid)
  2464. {
  2465.   octave_stream *retval = 0;
  2466.  
  2467.   if (instance)
  2468.     retval = instance->do_lookup (fid);
  2469.  
  2470.   return retval;
  2471. }
  2472.  
  2473. int
  2474. octave_stream_list::do_remove (int fid)
  2475. {
  2476.   int retval = -1;
  2477.  
  2478.   // Can't remove stdin (cin), stdout (cout), or stderr (cerr).
  2479.  
  2480.   if (fid > 2 && fid < curr_len)
  2481.     {
  2482.       octave_stream *os = list (fid);
  2483.  
  2484.       if (os)
  2485.     {
  2486.       delete os;
  2487.       list (fid) = 0;
  2488.       retval = 0;
  2489.     }
  2490.     }
  2491.  
  2492.   return retval;
  2493. }
  2494.  
  2495. int
  2496. octave_stream_list::do_remove (const octave_value& fid)
  2497. {
  2498.   int retval = -1;
  2499.  
  2500.   int i = get_file_number (fid);
  2501.  
  2502.   if (! error_state)
  2503.     retval = do_remove (i);
  2504.  
  2505.   return retval;
  2506. }
  2507.  
  2508. int
  2509. octave_stream_list::remove (int fid)
  2510. {
  2511.   int retval = -1;
  2512.  
  2513.   if (instance)
  2514.     retval = instance->do_remove (fid);
  2515.  
  2516.   return retval;
  2517. }
  2518.  
  2519. int
  2520. octave_stream_list::remove (const octave_value& fid)
  2521. {
  2522.   int retval = -1;
  2523.  
  2524.   if (instance)
  2525.     retval = instance->do_remove (fid);
  2526.  
  2527.   return retval;
  2528. }
  2529.  
  2530. void
  2531. octave_stream_list::do_clear (void)
  2532. {
  2533.   // Do flush stdout and stderr.
  2534.  
  2535.   list (0) -> flush ();
  2536.   list (1) -> flush ();
  2537.  
  2538.   // But don't delete them or stdin.
  2539.  
  2540.   for (int i = 3; i < curr_len; i++)
  2541.     {
  2542.       octave_stream *os = list (i);
  2543.  
  2544.       delete os;
  2545.  
  2546.       list (i) = 0;
  2547.     }
  2548. }
  2549.  
  2550. void
  2551. octave_stream_list::clear (void)
  2552. {
  2553.   if (instance)
  2554.     instance->do_clear ();
  2555. }
  2556.  
  2557. string_vector
  2558. octave_stream_list::do_get_info (int fid) const
  2559. {
  2560.   string_vector retval;
  2561.  
  2562.   octave_stream *os = do_lookup (fid);
  2563.  
  2564.   if (os)
  2565.     {
  2566.       retval.resize (3);
  2567.  
  2568.       retval(0) = os->name ();
  2569.       retval(1) = octave_stream::mode_as_string (os->mode ());
  2570.       retval(2) = oct_mach_info::float_format_as_string (os->float_format ());
  2571.     }
  2572.   else
  2573.     ::error ("invalid file id");
  2574.  
  2575.   return retval;
  2576. }
  2577.  
  2578. string_vector
  2579. octave_stream_list::do_get_info (const octave_value& fid) const
  2580. {
  2581.   string_vector retval;
  2582.  
  2583.   int conv_err = 0;
  2584.  
  2585.   int int_fid = convert_to_valid_int (fid, conv_err);
  2586.  
  2587.   if (! conv_err)
  2588.     retval = do_get_info (int_fid);
  2589.   else
  2590.     ::error ("file id must be valid integer");
  2591.  
  2592.   return retval;
  2593. }
  2594.  
  2595. string_vector
  2596. octave_stream_list::get_info (int fid)
  2597. {
  2598.   string_vector retval;
  2599.  
  2600.   if (instance)
  2601.     retval = instance->do_get_info (fid);
  2602.  
  2603.   return retval;
  2604. }
  2605.  
  2606. string_vector
  2607. octave_stream_list::get_info (const octave_value& fid)
  2608. {
  2609.   string_vector retval;
  2610.  
  2611.   if (instance)
  2612.     retval = instance->do_get_info (fid);
  2613.  
  2614.   return retval;
  2615. }
  2616.  
  2617. string
  2618. octave_stream_list::do_list_open_files (void) const
  2619. {
  2620.   string retval;
  2621.  
  2622.   // XXX FIXME XXX -- this should probably be converted to use sstream
  2623.   // when that is available.
  2624.   ostrstream buf;
  2625.  
  2626.   buf << "\n"
  2627.       << "  number  mode  arch       name\n"
  2628.       << "  ------  ----  ----       ----\n";
  2629.  
  2630.   for (int i = 0; i < curr_len; i++)
  2631.     {
  2632.       octave_stream *os = list (i);
  2633.  
  2634.       if (os)
  2635.     {
  2636.       string mode = octave_stream::mode_as_string (os->mode ());
  2637.  
  2638.       string arch =
  2639.         oct_mach_info::float_format_as_string (os->float_format ());
  2640.  
  2641.       string name = os->name ();
  2642.  
  2643.       buf.form ("  %4d     %-3s  %-9s  %s\n",
  2644.             i, mode.c_str (), arch.c_str (), name.c_str ());
  2645.     }
  2646.     }
  2647.  
  2648.   buf << "\n" << ends;
  2649.  
  2650.   char *tmp = buf.str ();
  2651.  
  2652.   retval = tmp;
  2653.  
  2654.   delete [] tmp;
  2655.  
  2656.   return retval;
  2657. }
  2658.  
  2659. string
  2660. octave_stream_list::list_open_files (void)
  2661. {
  2662.   string retval;
  2663.  
  2664.   if (instance)
  2665.     retval = instance->do_list_open_files ();
  2666.  
  2667.   return retval;
  2668. }
  2669.  
  2670. octave_value
  2671. octave_stream_list::do_open_file_numbers (void) const
  2672. {
  2673.   Matrix retval (1, curr_len, 0.0);
  2674.  
  2675.   int num_open = 0;
  2676.  
  2677.   // Skip stdin, stdout, and stderr.
  2678.  
  2679.   for (int i = 3; i < curr_len; i++)
  2680.     {
  2681.       if (list (i))
  2682.     retval (0, num_open++) = i;
  2683.     }
  2684.  
  2685.   retval.resize ((num_open > 0), num_open);
  2686.  
  2687.   return retval;
  2688. }
  2689.  
  2690. octave_value
  2691. octave_stream_list::open_file_numbers (void)
  2692. {
  2693.   octave_value retval;
  2694.  
  2695.   if (instance)
  2696.     retval = instance->do_open_file_numbers ();
  2697.  
  2698.   return retval;
  2699. }
  2700.  
  2701. int
  2702. octave_stream_list::do_get_file_number (const octave_value& fid) const
  2703. {
  2704.   int retval = -1;
  2705.  
  2706.   if (fid.is_string ())
  2707.     {
  2708.       string nm = fid.string_value ();
  2709.  
  2710.       // stdin (cin), stdout (cout), and stderr (cerr) are unnamed.
  2711.  
  2712.       for (int i = 3; i < curr_len; i++)
  2713.     {
  2714.       octave_stream *os = list (i);
  2715.  
  2716.       if (os && os->name () == nm)
  2717.         {
  2718.           retval = i;
  2719.           break;
  2720.         }
  2721.     }
  2722.     }
  2723.   else
  2724.     {
  2725.       int conv_err = 0;
  2726.  
  2727.       int int_fid = convert_to_valid_int (fid, conv_err);
  2728.  
  2729.       if (conv_err)
  2730.     ::error ("file id must be a string or integer value");
  2731.       else
  2732.     retval = int_fid;
  2733.     }
  2734.  
  2735.   return retval;
  2736. }
  2737.  
  2738. int
  2739. octave_stream_list::get_file_number (const octave_value& fid)
  2740. {
  2741.   int retval = -1;
  2742.  
  2743.   if (instance)
  2744.     retval = instance->do_get_file_number (fid);
  2745.  
  2746.   return retval;
  2747. }
  2748.  
  2749. /*
  2750. ;;; Local Variables: ***
  2751. ;;; mode: C++ ***
  2752. ;;; End: ***
  2753. */
  2754.